from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException
from redis.asyncio.client import Redis

from src.api.controllers.responses.auth import Token
from src.api.providers import Stub
from src.api.providers.auth import AuthProvider
from src.core.api_client.sms import SMSApiClient
from src.core.exceptions.user import UserPhoneNotExist
from src.core.utils.otp import generate_otp_code
from src.database.services import UserService

auth_router = APIRouter(
    prefix="/auth",
    tags=["auth"],
)


@auth_router.post("/login", description="Login request")
async def user_login(
    phone: str,
    redis: Annotated[Redis, Depends(Stub(Redis))],
    sms_api: Annotated[SMSApiClient, Depends(Stub(SMSApiClient))],
) -> None:
    otp_code = generate_otp_code()
    if not await sms_api.send_sms_with_otp_code(otp_code, phone):
        raise HTTPException(
            status_code=409, detail="Failed to send code to phone number"
        )

    await redis.set(otp_code, phone)
    return otp_code


@auth_router.post("/confirm", description="Confirm otp code and create user")
async def confirm_code(
    otp_code: str,
    redis: Annotated[Redis, Depends(Stub(Redis))],
    auth_provider: Annotated[AuthProvider, Depends(Stub(AuthProvider))],
    user_service: Annotated[UserService, Depends(Stub(UserService))],
) -> Token:
    phone = await redis.get(otp_code)
    phone = phone.decode("utf-8")

    if not phone:
        raise HTTPException(status_code=404, detail="Phone not found in rdb")

    try:
        user = await user_service.get_user_by_phone_number(phone)
    except UserPhoneNotExist:
        user = await user_service.create_user(phone)
    token = auth_provider.create_user_token(user.phone)
    await redis.delete(otp_code)

    return token
